/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.example.factorial;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.CorruptedFrameException;

import java.math.BigInteger;
import java.util.List;

/**
 * Decodes the binary representation of a {@link BigInteger} prepended
 * with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a
 * {@link BigInteger} instance.  For example, { 'F', 0, 0, 0, 1, 42 } will be
 * decoded into new BigInteger("42").
 *
 *
 * 这里是本例中,数据传输的重点
 *
 * 1. 将二进制解析出来 ,如果第一个字节为F,则是可以处理的数据
 * 1. 取一个32位的int,长度4字节. 这4个字节,存放的是实际传输数据的长度.
 * 1. 按长度读取数据, 将读取出来的数据,解析,并转为BigInteger
 *
 *
 */
public class BigIntegerDecoder extends ByteToMessageDecoder {

    /**
     * 解码器,重写ByteToMessageDecoder#decode
     * @param ctx           the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
     * @param in            the {@link ByteBuf} from which to read data
     * @param out           the {@link List} to which decoded messages should be added
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        /**
         * ctx : channel上下文
         * in : 进channel的数据流
         * out : 输出给下一个handler的数据
         */
        /**
         * in.readableBytes() , 当前拿到的, 可读取的数据
         */
        System.out.println("BigIntegerDecoder#decode in.length: "+in.readableBytes());
        // Wait until the length prefix is available.
        // 由于TCP传输数据的不确定性,拿到数据未必是全部数据
        // 所有这里判断一下 .
        // 由于已经确定 至少有5位的数据,那么小于5位的数据先不处理
        if (in.readableBytes() < 5) {
            return;
        }

        /**
         * 取得当前的读位置
         */
        int readerIndex = in.readerIndex();

        // Check the magic number.
        // 取得第一个字节
        // 判断 是不是约定好的字符F
        int magicNumber = in.readUnsignedByte();
        if (magicNumber != 'F') {
            //不是F,那么不是此handler处理的内容
            // 重置读位置
            in.readerIndex(readerIndex);
            // 业务处理 抛出异常,到处理器中,关闭channel
            throw new CorruptedFrameException("Invalid magic number: " + magicNumber);
        }


        // Wait until the whole data is available.
        // 读取一个int长度的数据,此数据应该是实际数据的长度
        // 一个int长度为4字节,并且读位置前进4字节
        int dataLength = in.readInt();
        // 判断剩余可读数据,与实际数据长度 . 是否足够读取.
        if (in.readableBytes() < dataLength) {
            //剩余可读数据,不足实际数据,那么本次不处理
            in.readerIndex(readerIndex);
            // 等待下次读取
            return;
        }

        // Convert the received data into a new BigInteger.
        // 读取到足够的数据
        // 剩余数据长度 >= 实际数据长度
        // 那么只读取实际数据长度的数据.
        byte[] decoded = new byte[dataLength];
        // 从数据流中读出,并放入到byte[]中
        in.readBytes(decoded);
        //转为BigInteger,并输出给下个handler
        out.add(new BigInteger(decoded));
    }
}
